/*
 *  Copyright 2011 yuxinlei.
 * 
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 * 
 *       http://www.apache.org/licenses/LICENSE-2.0
 * 
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *  under the License.
 */

package com.hudson.plugin.result.collector.server.datastore.internal.dao.impl;

import com.hudson.plugin.result.collector.server.datastore.dao.ProjectsEntityJpaController;
import com.hudson.plugin.result.collector.server.datastore.dao.exceptions.NonexistentEntityException;
import com.hudson.plugin.result.collector.server.datastore.dao.exceptions.PreexistingEntityException;
import com.hudson.plugin.result.collector.server.datastore.internal.entity.ProjectsEntity;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
import javax.persistence.EntityNotFoundException;
import com.hudson.plugin.result.collector.server.datastore.internal.entity.HudsonsEntity;
import com.hudson.plugin.result.collector.server.datastore.internal.entity.ViewsEntity;
import com.hudson.plugin.result.collector.server.datastore.internal.entity.BuildsEntity;
import java.util.ArrayList;
import java.util.Collection;
import com.hudson.plugin.result.collector.server.datastore.internal.entity.PromotionsEntity;

/**
 *
 * @author yuxinlei
 */
public class ProjectsEntityJpaControllerImpl implements ProjectsEntityJpaController {

    public ProjectsEntityJpaControllerImpl() {
        emf = Persistence.createEntityManagerFactory("reportdb");
    }
    private EntityManagerFactory emf = null;

    public EntityManager getEntityManager() {
        return emf.createEntityManager();
    }

    public void create(ProjectsEntity projectsEntity) throws PreexistingEntityException, Exception {
        if (projectsEntity.getBuildsesById() == null) {
            projectsEntity.setBuildsesById(new ArrayList<BuildsEntity>());
        }
        if (projectsEntity.getPromotionsesById() == null) {
            projectsEntity.setPromotionsesById(new ArrayList<PromotionsEntity>());
        }
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            HudsonsEntity hudsonsByHudsonId = projectsEntity.getHudsonsByHudsonId();
            if (hudsonsByHudsonId != null) {
                hudsonsByHudsonId = em.getReference(hudsonsByHudsonId.getClass(), hudsonsByHudsonId.getId());
                projectsEntity.setHudsonsByHudsonId(hudsonsByHudsonId);
            }
            ViewsEntity viewsByViewId = projectsEntity.getViewsByViewId();
            if (viewsByViewId != null) {
                viewsByViewId = em.getReference(viewsByViewId.getClass(), viewsByViewId.getId());
                projectsEntity.setViewsByViewId(viewsByViewId);
            }
            Collection<BuildsEntity> attachedBuildsesById = new ArrayList<BuildsEntity>();
            if(null!=projectsEntity.getBuildsesById())
            for (BuildsEntity buildsesByIdBuildsEntityToAttach : projectsEntity.getBuildsesById()) {
                buildsesByIdBuildsEntityToAttach = em.getReference(buildsesByIdBuildsEntityToAttach.getClass(), buildsesByIdBuildsEntityToAttach.getId());
                attachedBuildsesById.add(buildsesByIdBuildsEntityToAttach);
            }
            projectsEntity.setBuildsesById(attachedBuildsesById);
            Collection<PromotionsEntity> attachedPromotionsesById = new ArrayList<PromotionsEntity>();
            if(null!=projectsEntity.getPromotionsesById())
            for (PromotionsEntity promotionsesByIdPromotionsEntityToAttach : projectsEntity.getPromotionsesById()) {
                promotionsesByIdPromotionsEntityToAttach = em.getReference(promotionsesByIdPromotionsEntityToAttach.getClass(), promotionsesByIdPromotionsEntityToAttach.getId());
                attachedPromotionsesById.add(promotionsesByIdPromotionsEntityToAttach);
            }
            projectsEntity.setPromotionsesById(attachedPromotionsesById);
            em.persist(projectsEntity);
            if (hudsonsByHudsonId != null) {
                hudsonsByHudsonId.getProjectsesById().add(projectsEntity);
                hudsonsByHudsonId = em.merge(hudsonsByHudsonId);
            }
            if (viewsByViewId != null) {
                viewsByViewId.getProjectsesById().add(projectsEntity);
                viewsByViewId = em.merge(viewsByViewId);
            }
            if(null!=projectsEntity.getBuildsesById())
            for (BuildsEntity buildsesByIdBuildsEntity : projectsEntity.getBuildsesById()) {
                ProjectsEntity oldProjectsByProjectIdOfBuildsesByIdBuildsEntity = buildsesByIdBuildsEntity.getProjectsByProjectId();
                buildsesByIdBuildsEntity.setProjectsByProjectId(projectsEntity);
                buildsesByIdBuildsEntity = em.merge(buildsesByIdBuildsEntity);
                if (oldProjectsByProjectIdOfBuildsesByIdBuildsEntity != null) {
                    oldProjectsByProjectIdOfBuildsesByIdBuildsEntity.getBuildsesById().remove(buildsesByIdBuildsEntity);
                    oldProjectsByProjectIdOfBuildsesByIdBuildsEntity = em.merge(oldProjectsByProjectIdOfBuildsesByIdBuildsEntity);
                }
            }
            if(null!=projectsEntity.getPromotionsesById())
            for (PromotionsEntity promotionsesByIdPromotionsEntity : projectsEntity.getPromotionsesById()) {
                ProjectsEntity oldProjectsByProjectIdOfPromotionsesByIdPromotionsEntity = promotionsesByIdPromotionsEntity.getProjectsByProjectId();
                promotionsesByIdPromotionsEntity.setProjectsByProjectId(projectsEntity);
                promotionsesByIdPromotionsEntity = em.merge(promotionsesByIdPromotionsEntity);
                if (oldProjectsByProjectIdOfPromotionsesByIdPromotionsEntity != null) {
                    oldProjectsByProjectIdOfPromotionsesByIdPromotionsEntity.getPromotionsesById().remove(promotionsesByIdPromotionsEntity);
                    oldProjectsByProjectIdOfPromotionsesByIdPromotionsEntity = em.merge(oldProjectsByProjectIdOfPromotionsesByIdPromotionsEntity);
                }
            }
            em.getTransaction().commit();
        } catch (Exception ex) {
            if (findProjectsEntity(projectsEntity.getId()) != null) {
                throw new PreexistingEntityException("ProjectsEntity " + projectsEntity + " already exists.", ex);
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void edit(ProjectsEntity projectsEntity) throws NonexistentEntityException, Exception {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            ProjectsEntity persistentProjectsEntity = em.find(ProjectsEntity.class, projectsEntity.getId());
            HudsonsEntity hudsonsByHudsonIdOld = persistentProjectsEntity.getHudsonsByHudsonId();
            HudsonsEntity hudsonsByHudsonIdNew = projectsEntity.getHudsonsByHudsonId();
            ViewsEntity viewsByViewIdOld = persistentProjectsEntity.getViewsByViewId();
            ViewsEntity viewsByViewIdNew = projectsEntity.getViewsByViewId();
            Collection<BuildsEntity> buildsesByIdOld = persistentProjectsEntity.getBuildsesById();
            Collection<BuildsEntity> buildsesByIdNew = projectsEntity.getBuildsesById();
            Collection<PromotionsEntity> promotionsesByIdOld = persistentProjectsEntity.getPromotionsesById();
            Collection<PromotionsEntity> promotionsesByIdNew = projectsEntity.getPromotionsesById();
            if (hudsonsByHudsonIdNew != null) {
                hudsonsByHudsonIdNew = em.getReference(hudsonsByHudsonIdNew.getClass(), hudsonsByHudsonIdNew.getId());
                projectsEntity.setHudsonsByHudsonId(hudsonsByHudsonIdNew);
            }
            if (viewsByViewIdNew != null) {
                viewsByViewIdNew = em.getReference(viewsByViewIdNew.getClass(), viewsByViewIdNew.getId());
                projectsEntity.setViewsByViewId(viewsByViewIdNew);
            }
            Collection<BuildsEntity> attachedBuildsesByIdNew = new ArrayList<BuildsEntity>();
            if(null!=buildsesByIdNew)
            for (BuildsEntity buildsesByIdNewBuildsEntityToAttach : buildsesByIdNew) {
                buildsesByIdNewBuildsEntityToAttach = em.getReference(buildsesByIdNewBuildsEntityToAttach.getClass(), buildsesByIdNewBuildsEntityToAttach.getId());
                attachedBuildsesByIdNew.add(buildsesByIdNewBuildsEntityToAttach);
            }
            buildsesByIdNew = attachedBuildsesByIdNew;
            projectsEntity.setBuildsesById(buildsesByIdNew);
            Collection<PromotionsEntity> attachedPromotionsesByIdNew = new ArrayList<PromotionsEntity>();
            if(null!=promotionsesByIdNew)
            for (PromotionsEntity promotionsesByIdNewPromotionsEntityToAttach : promotionsesByIdNew) {
                promotionsesByIdNewPromotionsEntityToAttach = em.getReference(promotionsesByIdNewPromotionsEntityToAttach.getClass(), promotionsesByIdNewPromotionsEntityToAttach.getId());
                attachedPromotionsesByIdNew.add(promotionsesByIdNewPromotionsEntityToAttach);
            }
            promotionsesByIdNew = attachedPromotionsesByIdNew;
            projectsEntity.setPromotionsesById(promotionsesByIdNew);
            projectsEntity = em.merge(projectsEntity);
            if (hudsonsByHudsonIdOld != null && !hudsonsByHudsonIdOld.equals(hudsonsByHudsonIdNew)) {
                hudsonsByHudsonIdOld.getProjectsesById().remove(projectsEntity);
                hudsonsByHudsonIdOld = em.merge(hudsonsByHudsonIdOld);
            }
            if (hudsonsByHudsonIdNew != null && !hudsonsByHudsonIdNew.equals(hudsonsByHudsonIdOld)) {
                hudsonsByHudsonIdNew.getProjectsesById().add(projectsEntity);
                hudsonsByHudsonIdNew = em.merge(hudsonsByHudsonIdNew);
            }
            if (viewsByViewIdOld != null && !viewsByViewIdOld.equals(viewsByViewIdNew)) {
                viewsByViewIdOld.getProjectsesById().remove(projectsEntity);
                viewsByViewIdOld = em.merge(viewsByViewIdOld);
            }
            if (viewsByViewIdNew != null && !viewsByViewIdNew.equals(viewsByViewIdOld)) {
                viewsByViewIdNew.getProjectsesById().add(projectsEntity);
                viewsByViewIdNew = em.merge(viewsByViewIdNew);
            }
            if(null!=buildsesByIdOld)
            for (BuildsEntity buildsesByIdOldBuildsEntity : buildsesByIdOld) {
                if (!buildsesByIdNew.contains(buildsesByIdOldBuildsEntity)) {
                    buildsesByIdOldBuildsEntity.setProjectsByProjectId(null);
                    buildsesByIdOldBuildsEntity = em.merge(buildsesByIdOldBuildsEntity);
                }
            }
            if(null!=buildsesByIdNew)
            for (BuildsEntity buildsesByIdNewBuildsEntity : buildsesByIdNew) {
                if (!buildsesByIdOld.contains(buildsesByIdNewBuildsEntity)) {
                    ProjectsEntity oldProjectsByProjectIdOfBuildsesByIdNewBuildsEntity = buildsesByIdNewBuildsEntity.getProjectsByProjectId();
                    buildsesByIdNewBuildsEntity.setProjectsByProjectId(projectsEntity);
                    buildsesByIdNewBuildsEntity = em.merge(buildsesByIdNewBuildsEntity);
                    if (oldProjectsByProjectIdOfBuildsesByIdNewBuildsEntity != null && !oldProjectsByProjectIdOfBuildsesByIdNewBuildsEntity.equals(projectsEntity)) {
                        oldProjectsByProjectIdOfBuildsesByIdNewBuildsEntity.getBuildsesById().remove(buildsesByIdNewBuildsEntity);
                        oldProjectsByProjectIdOfBuildsesByIdNewBuildsEntity = em.merge(oldProjectsByProjectIdOfBuildsesByIdNewBuildsEntity);
                    }
                }
            }
            if(null!=promotionsesByIdOld)
            for (PromotionsEntity promotionsesByIdOldPromotionsEntity : promotionsesByIdOld) {
                if (!promotionsesByIdNew.contains(promotionsesByIdOldPromotionsEntity)) {
                    promotionsesByIdOldPromotionsEntity.setProjectsByProjectId(null);
                    promotionsesByIdOldPromotionsEntity = em.merge(promotionsesByIdOldPromotionsEntity);
                }
            }
            if(null!=promotionsesByIdNew)
            for (PromotionsEntity promotionsesByIdNewPromotionsEntity : promotionsesByIdNew) {
                if (!promotionsesByIdOld.contains(promotionsesByIdNewPromotionsEntity)) {
                    ProjectsEntity oldProjectsByProjectIdOfPromotionsesByIdNewPromotionsEntity = promotionsesByIdNewPromotionsEntity.getProjectsByProjectId();
                    promotionsesByIdNewPromotionsEntity.setProjectsByProjectId(projectsEntity);
                    promotionsesByIdNewPromotionsEntity = em.merge(promotionsesByIdNewPromotionsEntity);
                    if (oldProjectsByProjectIdOfPromotionsesByIdNewPromotionsEntity != null && !oldProjectsByProjectIdOfPromotionsesByIdNewPromotionsEntity.equals(projectsEntity)) {
                        oldProjectsByProjectIdOfPromotionsesByIdNewPromotionsEntity.getPromotionsesById().remove(promotionsesByIdNewPromotionsEntity);
                        oldProjectsByProjectIdOfPromotionsesByIdNewPromotionsEntity = em.merge(oldProjectsByProjectIdOfPromotionsesByIdNewPromotionsEntity);
                    }
                }
            }
            em.getTransaction().commit();
        } catch (Exception ex) {
            String msg = ex.getLocalizedMessage();
            if (msg == null || msg.length() == 0) {
                int id = projectsEntity.getId();
                if (findProjectsEntity(id) == null) {
                    throw new NonexistentEntityException("The projectsEntity with id " + id + " no longer exists.");
                }
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void destroy(int id) throws NonexistentEntityException {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            ProjectsEntity projectsEntity;
            try {
                projectsEntity = em.getReference(ProjectsEntity.class, id);
                projectsEntity.getId();
            } catch (EntityNotFoundException enfe) {
                throw new NonexistentEntityException("The projectsEntity with id " + id + " no longer exists.", enfe);
            }
            HudsonsEntity hudsonsByHudsonId = projectsEntity.getHudsonsByHudsonId();
            if (hudsonsByHudsonId != null) {
                hudsonsByHudsonId.getProjectsesById().remove(projectsEntity);
                hudsonsByHudsonId = em.merge(hudsonsByHudsonId);
            }
            ViewsEntity viewsByViewId = projectsEntity.getViewsByViewId();
            if (viewsByViewId != null) {
                viewsByViewId.getProjectsesById().remove(projectsEntity);
                viewsByViewId = em.merge(viewsByViewId);
            }
            Collection<BuildsEntity> buildsesById = projectsEntity.getBuildsesById();
            if(null!=buildsesById)
            for (BuildsEntity buildsesByIdBuildsEntity : buildsesById) {
                buildsesByIdBuildsEntity.setProjectsByProjectId(null);
                buildsesByIdBuildsEntity = em.merge(buildsesByIdBuildsEntity);
            }
            Collection<PromotionsEntity> promotionsesById = projectsEntity.getPromotionsesById();
            if(null!=promotionsesById)
            for (PromotionsEntity promotionsesByIdPromotionsEntity : promotionsesById) {
                promotionsesByIdPromotionsEntity.setProjectsByProjectId(null);
                promotionsesByIdPromotionsEntity = em.merge(promotionsesByIdPromotionsEntity);
            }
            em.remove(projectsEntity);
            em.getTransaction().commit();
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }


    public ProjectsEntity findProjectsEntity(int id) {
        EntityManager em = getEntityManager();
        try {
            return em.find(ProjectsEntity.class, id);
        } finally {
            em.close();
        }
    }


    public List<Integer> findProjectsEntityByHudsonIdAndName(Integer hudsonId, String projectName) {
        EntityManager em = getEntityManager();
        try {
            Query query = em.createNativeQuery(
                    "select p.id from projects p where p.project_name = :project_name and p.hudson_id = :hudson_id"  );
            query.setParameter("project_name", projectName.trim());
            query.setParameter("hudson_id", hudsonId);
            List<Integer> projectsId = query.getResultList();
            return projectsId;
        } finally {
            em.close();
        }
    }

}
